package cn.ultrarisk.sprinx.mybatis.query;

import cn.ultrarisk.sprinx.mybatis.config.MybatisContext;
import cn.ultrarisk.sprinx.util.Utilities;
import org.apache.commons.beanutils.PropertyUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Updater
 *
 * @author sevendlong(lin23871@163.com)
 * @date 2014/9/30
 * @since V1.0
 */
public class Updater {
    private Map<String, Field> fields;

    public static Updater update(String key, Object value) {
        return update(key, Opt.EQ, value);
    }

    public static Updater update(String key, Opt opt, Object value) {
        Updater updater = new Updater();
        updater.addField(key, opt, value);
        return updater;
    }

    public Updater() {
        this.fields = new HashMap<String, Field>();
    }

    public Map<String, Field> getFields() {
        return fields;
    }

    public Updater addField(String key, Object value) {
        this.fields.put(key, new Field(key, Opt.EQ, value));
        return this;
    }

    public Updater addField(String key, Opt symbol, Object value) {
        this.fields.put(key, new Field(key, symbol, value));
        return this;
    }

    public static <T> Updater fromEntity(T entity, List<String> updateColumns, boolean withNullField, String idColumn, Map<String, String> columnPropertyMap) {
        Updater updater = new Updater();
        try {
            for (String updateColumn : updateColumns) {
                if (idColumn.equals(updateColumn)) {
                    continue;
                }
                String updateProperty = columnPropertyMap.get(updateColumn);
                if (Utilities.isEmpty(updateProperty)) {
                    continue;
                }
                Object updatePropertyVal = PropertyUtils.getProperty(entity, updateProperty);
                if (withNullField || updatePropertyVal != null) {
                    updater.addField(updateColumn, updatePropertyVal);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return updater;
    }

    public Map<String, Object> toMap() {
        Map<String, String> opt = new HashMap<String, String>();
        opt.put("EQ", Opt.EQ.value());
        opt.put("ADD", Opt.ADD.value());
        opt.put("SUB", Opt.SUB.value());

        Map<String, Object> map = new HashMap<String, Object>();
        map.put(MybatisContext.UPDATE_OPTS, opt);
        map.put(MybatisContext.UPDATE_FIELDS, fields);
        return map;
    }

    public Map<String, Object> toMap(String tableName) {
        Map<String, Object> map = this.toMap();
        if (tableName != null && tableName.length() > 0) {
            map.put(MybatisContext.TABLE_NAME, tableName);
        }
        return map;
    }

    public Map<String, Object> toMap(String tableName, Query query) {
        Map<String, Object> map = this.toMap(tableName);
        map.putAll(query.toMap());
        return map;
    }

    private static class Field {
        private String key;
        private Opt opt;
        private Object value;

        public Field(String key, Opt opt, Object value) {
            this.key = key;
            this.opt = opt;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

        public Opt getOpt() {
            return opt;
        }

        public String getOptValue() {
            return this.opt.value();
        }

        public Object getValue() {
            return value;
        }
    }

    /**
     * 更新运算符
     *
     * @author sevendlong(lin23871@163.com)
     * @date 2014/9/30
     * @since V1.0
     */
    public static enum Opt {
        EQ("eq"),
        ADD("add"),
        SUB("sub");

        private String value;
        Opt(String value) {
            this.value = value;
        }

        public String value() {
            return this.value;
        }
    }
}
